package nancal.mp.service


import com.aliyuncs.DefaultAcsClient
import com.aliyuncs.IAcsClient
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse
import com.aliyuncs.profile.DefaultProfile
import nancal.mp.db.mongo.MobileCodeModuleEnum
import nancal.mp.db.mongo.entity.log.MobileCodeLog
import nancal.mp.db.mongo.mor
import nancal.mp.db.redis.rer
import nancal.mp.service.sms.SmsStrategy
import nbcp.base.comm.ApiResult
import nbcp.base.comm.StringMap
import nbcp.base.extend.HasValue
import nbcp.base.extend.ToJson
import nbcp.myoql.db.mongo.query
import org.bson.types.ObjectId
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
import java.time.LocalDateTime

@Service
@ConditionalOnProperty("app.sms.aliyun.domain")
class AliSmsService : SmsStrategy {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }

    @Value("\${app.sms.aliyun.accessKeyId}")
    var accessKeyId: String = "";

    @Value("\${app.sms.aliyun.accessKeySecret}")
    var accessKeySecret: String = "";

    @Value("\${app.sms.aliyun.product:}")
    var product: String = "";

    @Value("\${app.sms.aliyun.domain:}")
    var domain: String = "";

    @Value("\${app.sms.aliyun.signName}")
    var signName: String = ""


    /**
     * SMS_223587410: 您的验证码是${code}。请于5分钟内完成验证，若非本人操作，请忽略本短信。
     */
    var templateCodeMap = mapOf(
        MobileCodeModuleEnum.Login to "SMS_223587410",
        MobileCodeModuleEnum.Registe to "SMS_223587410",
        MobileCodeModuleEnum.ForgetPassword to "SMS_223587410",
        MobileCodeModuleEnum.ChangeMobile to "SMS_223587410"
    )


    /**
     * 获取验证码
     */
    override fun getSmsCode(
        productLineCode: String,
        module: MobileCodeModuleEnum,
        recvMobile: String
    ): ApiResult<String> {
        return ApiResult.of(rer.sys.smsCode(module.toString() + "-" + recvMobile).get());
    }


    /**
     * 通用短信验证码
     */
    override fun sendSmsCode(
        productLineCode: String,
        module: MobileCodeModuleEnum,
        recvMobile: String,
        code: String,
        lang: String
    ): ApiResult<String> {
        var map = StringMap();
        map.put("code", code)

        return sendSmsCode(module, templateCodeMap.get(module)!!, recvMobile, code, map.ToJson())
    }

    override fun sendSmsNotification(
        productLineCode: String,
        module: MobileCodeModuleEnum,
        recvMobile: String,
        lang: String,
        params: List<String>
    ): ApiResult<String> {
        TODO("Not yet implemented")
    }

    /**
     * @param recvMobile 不带 +86 的手机号。
     */
//    fun sendSmsCode(module: MobileCodeModuleEnum, recvMobile: String, code: String): String {
//        var map = StringMap();
//        map.put("code", code)
//
//        var registe_code = mapOf(
//            MobileCodeModuleEnum.Registe to "SMS_206430272",
//            MobileCodeModuleEnum.ForgetPassword to "SMS_206895659",
//            MobileCodeModuleEnum.ChangeMobile to "SMS_207948930"
//        )
//
//
//        return sendSmsCode(module.toString(), registe_code.get(module)!!, recvMobile, code, map.ToJson())
//    }

    private fun sendSmsCode(
        module: MobileCodeModuleEnum,
        templateCode: String,
        recvMobile: String,
        code: String,
        paramString: String
    ): ApiResult<String> {
        //可自助调整超时时间
//        System.setProperty("sun.net.client.defaultConnectTimeout", "10000")
//        System.setProperty("sun.net.client.defaultReadTimeout", "10000")

        //规则
        var msg = check(module, recvMobile)
        if (msg.HasValue) {
            return ApiResult.error(msg, 500);
        }

        var smsLog = MobileCodeLog();
        smsLog.module = module
        smsLog.mobile = recvMobile;
        smsLog.templateCode = templateCode;
        smsLog.param = paramString;
        smsLog.id = ObjectId().toString();

        //初始化acsClient,暂不支持region化
        val profile = DefaultProfile.getProfile("default", accessKeyId, accessKeySecret)
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain)
        val acsClient = DefaultAcsClient(profile) as IAcsClient

        //组装请求对象-具体描述见控制台-文档部分内容
        val request = SendSmsRequest()

        request.phoneNumbers = recvMobile;
        request.signName = signName
        request.templateCode = templateCode
        request.templateParam = paramString

        request.outId = smsLog.id
        //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");


        //hint 此处可能会抛出异常，注意catch
        var response: SendSmsResponse? = null;

        try {
            if (recvMobile.startsWith("110") == false) {
                response = acsClient.getAcsResponse(request)


                if (response == null) {
                    var err = "发送短信时失败"
                    smsLog.errorMessage = err;
                    return ApiResult.error(err, 500);
                }

                smsLog.result = response;

                if (response.code == null || response.code != "OK") {
                    return ApiResult.error(response.message, 500);
                }

                smsLog.bizId = response.bizId
            }

            rer.sys.smsCode(module.toString() + "-" + recvMobile).set(code);
        } catch (e: Exception) {
            var err = e.message ?: "发送短信时失败"

            smsLog.errorMessage = err;
            return ApiResult.error(err, 500);
        } finally {
            mor.log.mobileCodeLog.doInsert(smsLog)
        }


        return ApiResult()
    }

    /**
     * 规则：每个模块业务每小时15条，每自然日45条。
     */
    fun check(module: MobileCodeModuleEnum, recvMobile: String): String {
        var now = LocalDateTime.now()
        now.minusMinutes(now.minute.toLong())
        now.minusSeconds(now.second.toLong())


        var hourCount = mor.log.mobileCodeLog.query()
            .where { it.module mongoEquals module }
            .where { it.mobile mongoEquals recvMobile }
            .where { it.createAt greaterThan now }
            .orderByDesc { it.createAt }
            .count()

        if (hourCount > 15) {
            return "操作过于频繁，请1分钟后重试！"
        }

        now.minusHours(now.hour.toLong())

        var dayCount = mor.log.mobileCodeLog.query()
            .where { it.module mongoEquals module }
            .where { it.mobile mongoEquals recvMobile }
            .where { it.createAt greaterThan now }
            .orderByDesc { it.createAt }
            .count()

        if (dayCount > 45) {
            return "操作过于频繁，请1分钟后重试！"
        }

        return "";
    }
}
